package com.shawn.dubbo.api;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mongodb.client.result.UpdateResult;
import com.shawn.commons.utils.CommentType;
import com.shawn.dubbo.service.TimeLineService;
import com.shawn.dubbo.utils.IdWorker;
import com.shawn.model.mongo.Comment;
import com.shawn.model.mongo.Movement;
import com.shawn.model.mongo.MovementTimeLine;
import com.shawn.model.vo.PageResult;
import org.apache.dubbo.config.annotation.DubboService;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@DubboService
public class MovementApiImpl implements MovementApi{
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private IdWorker idWorker;



    @Autowired
    private TimeLineService timeLineService;

    @Override
    public String saveMovement(Movement movement) {
        Long pid = idWorker.getNextId("movement");;
        movement.setPid(pid);
        //获取用户id
        Long userId = movement.getUserId();
        movement.setCreated(new Date().getTime());
        //保存动态
        Movement saveMovement = mongoTemplate.save(movement);

        //根据id查询朋友信息,并生成动态时间线表
        timeLineService.saveTimeline(userId, saveMovement);
        return saveMovement.getId().toHexString();
    }

    /**
     * 分页查询
     *
     * @param page     页面
     * @param pageSize 页面大小
     * @param userId   用户id
     * @return {@link IPage}<{@link Movement}>
     */
    @Override
    public IPage<Movement> selectByPage(Integer page, Integer pageSize, Long userId) {
        Query query = new Query(Criteria.where("userId").is(userId))
                .addCriteria(Criteria.where("state").is(1))//过滤不良信息
                ;
        //查询动态总数
        long count = mongoTemplate.count(query, Movement.class);
        query.skip((long) (page - 1) *pageSize)
                .limit(pageSize)
                .with(Sort.by(Sort.Order.desc("created")));
        List<Movement> movements = mongoTemplate.find(query, Movement.class);
        Page<Movement> movementPage = new Page<>();
        movementPage.setCurrent(page);
        movementPage.setPages(pageSize);
        movementPage.setTotal(count);
        movementPage.setRecords(movements);
        return movementPage;
    }

    /**
     * 得到朋友动态
     *
     * @param page     页面
     * @param pageSize 页面大小
     * @param userId   用户id
     * @return {@link IPage}<{@link Movement}>
     */
    @Override
    public IPage<Movement> getFriendsDynamics(Integer page, Integer pageSize, Long userId) {
        //分页查询时间线表所有动态id
        Query query = new Query(Criteria.where("friendId").is(userId));

        query.with(Sort.by(Sort.Order.desc("created")));
        List<MovementTimeLine> timeLines = mongoTemplate.find(query, MovementTimeLine.class);
        //获取所有时间线表MovementId 集合
        List<ObjectId> objectIdList = timeLines.stream().map(MovementTimeLine::getMovementId).collect(Collectors.toList());
        Query movQuery = new Query()
                .addCriteria(Criteria.where("id").in(objectIdList))
                //过滤所有未过审动态
                .addCriteria(Criteria.where("state").is(1));
        long count = mongoTemplate.count(movQuery, Movement.class);
        if (count==0){
            return new Page<>();
        }
        movQuery.skip((long) (page - 1) *pageSize)
                .limit(pageSize)
                .with(Sort.by(Sort.Order.desc("created")));
        //根据时间线表MovementId查询所有动态信息
        List<Movement> movements = mongoTemplate.find(movQuery,Movement.class);
        Page<Movement> movementPage = new Page<>();
        movementPage.setCurrent(page);
        movementPage.setPages(pageSize);
        movementPage.setTotal(count);
        movementPage.setRecords(movements);
        return movementPage;
    }

    /**
     * 随机构造指定条数动态
     *
     * @param movementCount 运动计数
     * @return {@link List}<{@link Movement}>
     */
    @Override
    public List<Movement> getRandomMovement(Integer movementCount,Long userId) {

        //创建统计对象,设置统计参数 Movement 对应表 Aggregation.sample(movementCount)对应统计方法及参数
        TypedAggregation<Movement> aggregation = TypedAggregation.newAggregation(Movement.class,
                Aggregation.sample(movementCount),
                //过滤不良信息
                Aggregation.match(Criteria.where("state").is(1)),
                Aggregation.match(Criteria.where("userId").ne(userId)),
                //按发布时间降序排序
                Aggregation.sort(Sort.by(Sort.Order.desc("created"))));
        //Movement.class 返回值封装类型
        AggregationResults<Movement> results = mongoTemplate.aggregate(aggregation, Movement.class);
        return results.getMappedResults();
    }

    @Override
    public List<Movement> getByIdList(List<Long> pidList,Long userId) {
        Query query = new Query(Criteria.where("pid").in(pidList))
                .addCriteria(Criteria.where("userId").ne(userId));
        return mongoTemplate.find(query, Movement.class);
    }

    @Override
    public Movement getById(String id) {
        Query query = new Query(Criteria.where("id").is(new ObjectId(id)));
        return mongoTemplate.findOne(query,Movement.class);
    }

    @Override
    public Integer operateLikeOrLove(String id,Long userId, CommentType commentType, Number number) {
        String columnName = Objects.equals(commentType.getType(), CommentType.LIKE.getType())?"likeCount":"loveCount";
        Query query = new Query(Criteria.where("id").is(new ObjectId(id)));
        Update update = new Update().inc(columnName, number);
        FindAndModifyOptions options = new FindAndModifyOptions();
        //如果找到即更新
        options.upsert(true);
        //返回最新生成pid字段
        options.returnNew(true);
        Movement movement = mongoTemplate.findAndModify(query, update, options, Movement.class);
        if (movement==null){
            return 0;
        }
        if (number.equals(1)) {
            //生成评论
            Comment comment = new Comment();
            comment.setPublishId(new ObjectId(id));
            comment.setCommentType(commentType.getType());
            comment.setUserId(userId);
            comment.setPublishUserId(movement.getUserId());
            comment.setCreated(new Date().getTime());
            mongoTemplate.save(comment);
            //将评论数据保存进redis
        }else {
            //删除点赞 喜欢评论
            Query comQuery = new Query();
            comQuery.addCriteria(Criteria.where("publishId").is(new ObjectId(id)))
                    .addCriteria(Criteria.where("userId").is(userId))
                    .addCriteria(Criteria.where("commentType").is(commentType.getType()));
            //删除评论表
            mongoTemplate.remove(comQuery, Comment.class);
        }
        //返回点击数 作为Movement
        return movement.getCommentTypeCount(commentType.getType());
    }

    @Override
    public PageResult<Movement> selectByCondition(Integer page, Integer pageSize, Long userId, Integer state) {

        Query query = new Query();
        if (!Objects.isNull(userId)){
            query.addCriteria(Criteria.where("userId").is(userId));
        }
        if (!Objects.isNull(state)){
            if (state!=3){
                query.addCriteria(Criteria.where("state").is(state));
            }
        }
        long count = mongoTemplate.count(query, Movement.class);
        if (count==0){
            return new PageResult<>();
        }
        query.skip((long) (page - 1) *pageSize)
                .limit(pageSize);
        List<Movement> movements = mongoTemplate.find(query, Movement.class);

        return new PageResult<>(page,pageSize,(int)count,movements);
    }

    /**
     * 审核更新动态状态
     *
     * @param movement 运动
     */
    @Override
    public void update(Movement movement) {
        Query query = new Query(Criteria.where("id").is(movement.getId()));
        Update update = new Update();
        update.set("state",movement.getState());
        mongoTemplate.updateFirst(query,update,Movement.class);
    }

    @Override
    public String passOrNot(List<String> ids,Integer state) {
        List<ObjectId> idList = ids.stream().map(ObjectId::new).collect(Collectors.toList());
        Query query = new Query(Criteria.where("id").in(idList));
        Update update = new Update().set("state",state);
        UpdateResult updateResult = mongoTemplate.updateMulti(query, update, Movement.class);
        long count = updateResult.getMatchedCount();
        return count>0?"修改成功!":"修改失败!";
    }
}
